package com.cloud.base.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.cloud.api.annotation.LocalLock;
import com.cloud.api.constants.MobileVo;
import com.cloud.api.constants.RedisConstants;
import com.cloud.api.constants.SmsTemplates;
import com.cloud.api.constants.SmsType;
import com.cloud.api.utils.WebHttpApi;
import com.cloud.base.service.ISmsService;
import com.cloud.core.exception.MyException;
import com.cloud.mybatis.config.LoginHolder;
import com.fasterxml.jackson.databind.JsonNode;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.time.*;

@Service("mySmsService")
@Slf4j
public class SmsServiceImpl implements ISmsService {


    @Autowired
    private SmsTemplates smsTemplates;
    @Resource(name = "myRedis")
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private SymmetricCrypto symmetricCrypto;

    @LocalLock(key = "SMS_RATE",value = "#{clientId}", expire = 60000)
    public void sendSmsCode(String clientId,MobileVo para) {
        log.info(JSONUtil.toJsonStr(para));
        if(null==clientId || clientId.trim().length()==0)
            throw new MyException("wds.exception.clientId");
        boolean success=true;
        try {
            if(success) {
                String code = RandomUtil.randomNumbers(6);
                switch (para.getType()) {
                    case "LOGIN":
                        redisTemplate.opsForValue().set(RedisConstants.LOGIN_CODE + para.getMobile(), code, Duration.ofMinutes(5));
                        sendSms(para.getMobile(), smsTemplates.getLoginTemplate(), JSONUtil.createObj().putOnce("code", code));
                        break;
                    case "CHANGE-MOBILE":
                        redisTemplate.opsForValue().set(RedisConstants.CHANGE_MOBILE + para.getMobile(), code, Duration.ofMinutes(5));
                        sendSms(para.getMobile(), smsTemplates.getChangeMobile(), JSONUtil.createObj().putOnce("code", code));
                        break;
                    case "USER-UNREG":
                        redisTemplate.opsForValue().set(RedisConstants.USER_UNREG + para.getMobile(), code, Duration.ofMinutes(5));
                        sendSms(para.getMobile(), smsTemplates.getUserUnreg(), JSONUtil.createObj().putOnce("code", code));
                        break;
                    case "CONTROL-VEHICLE":
                        redisTemplate.opsForValue().set("CONTROL_VEHICLE:" + para.getMobile(), code, Duration.ofMinutes(5));
                        sendSms(para.getMobile(), smsTemplates.getLoginTemplate(), JSONUtil.createObj().putOnce("code", code));
                        break;
                    case "SERVICE-STATION":
                        sendServiceStationSmsCode(para.getMobile());
                        break;
                }
            }else{
                throw new MyException("wds.exception.smsFrequency",105);
            }
        } catch (MyException e) {
            if ("wds.exception.smsFrequencyExceeded".equals(e.getErrorCode())) { // 使用 getErrorCode() 方法
                throw e; // 直接抛出 wds.exception.smsFrequencyExceeded
            }
            e.printStackTrace();
            throw new MyException("wds.exception.smsError");
        } catch (Exception e) {
            e.printStackTrace();
            throw new MyException("wds.exception.smsError");
        } finally {
            // lockTemplate.releaseLock(lock);
        }
    }


    private void sendServiceStationSmsCode(String mobile) {
        String redisKey = "SERVICE_STATION:" + mobile + ":count";
        String redisCodeKey = "SERVICE_STATION:" + mobile + ":code";
        String redisUsedKey = "SERVICE_STATION:" + mobile + ":used";

        // 检查发送次数是否超过限制
        Long count = redisTemplate.opsForValue().increment(redisKey);
        long currentTimeMillis = System.currentTimeMillis();
        long endOfDay = calculateTimeUntilEndOfDay(currentTimeMillis);
        if (count == 1) {
            redisTemplate.expire(redisKey, Duration.ofMillis(endOfDay));
        } else if (count > 5) {
            throw new MyException("wds.exception.smsFrequencyExceeded");
        }

        // 生成验证码
        String code = RandomUtil.randomNumbers(6);

        // 存储验证码和未使用标志
        redisTemplate.opsForValue().set(redisCodeKey, code, Duration.ofMinutes(5));
        redisTemplate.opsForValue().set(redisUsedKey, "false", Duration.ofMinutes(5));

        // 发送短信
        sendSms(mobile, smsTemplates.getLoginTemplate(), JSONUtil.createObj().putOnce("code", code));
    }

    private long calculateTimeUntilEndOfDay(long currentTime) {
        // 获取当前日期，使用东八区时间
        Instant instant = Instant.ofEpochMilli(currentTime);
        ZoneId zoneId = ZoneId.of("Asia/Shanghai");
        LocalDate currentDate = instant.atZone(zoneId).toLocalDate();

        // 计算第二天0点的时间戳，使用东八区时间
        LocalDateTime endOfDay = currentDate.plusDays(1).atStartOfDay();
        ZonedDateTime zonedDateTime = endOfDay.atZone(zoneId); // 使用 atZone 方法生成 ZonedDateTime
        long expirationTime = zonedDateTime.toInstant().toEpochMilli(); // 正确获取时间戳

        // 计算时间差（毫秒）
        return expirationTime - currentTime;
    }



    @Override
    public void sendSmsCodeVehicle(SmsType para) {
        MultiValueMap<String,String> param = new LinkedMultiValueMap<>();
        param.add("userId",LoginHolder.getLoginUser().getUid());
        JsonNode jsonNode = WebHttpApi.get("http://sys-permit/sys-permit/user-dept/getUserById", param);
        if (jsonNode.get("code").asInt() != 200) {
            throw new MyException("wds.exception.smsError");
        }
        JsonNode data = jsonNode.get("data");
        JsonNode mobile = data.get("mobileDc");
        if (mobile.isNull()) {
            throw new MyException("wds.exception.smsError");
        }

//        String mobile = LoginHolder.getLoginUser().getMobile();
        MobileVo mobileVo = new MobileVo();
        mobileVo.setMobile(symmetricCrypto.decryptStr(mobile.asText()));
//        mobileVo.setMobile("11111111111");
        mobileVo.setType(para.getType());
        sendSmsCode(para.getClientId(), mobileVo);
    }

    @Autowired
    private Client smsClient;

    public void sendSms(String mobile, String templateCode, JSONObject json) {
        SendSmsRequest sms = new SendSmsRequest();
        sms.setPhoneNumbers(mobile);
        sms.setTemplateCode(templateCode);
        sms.setSignName(smsTemplates.getSignName());

        sms.setTemplateParam(JSONUtil.toJsonStr(json));
        log.info(JSONUtil.toJsonStr(sms));
        try {
            SendSmsResponse resp = smsClient.sendSms(sms);
            if (resp.getBody().getCode().equals("OK")) {
                log.info("短信发送成功");
            }else{
                log.error(resp.getBody().getMessage());
                throw new MyException(resp.getBody().getMessage());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void checkSmsRate(String clientId, String mobile) {
        Object send = redisTemplate.opsForValue().get(RedisConstants.SMS_RATE + clientId);
        if (send != null) {
            throw new MyException("wds.exception.smsFrequency");
        }
    }
}
